package test;

import jnr.ffi.Platform;
import jnr.ffi.Pointer;
import jnr.ffi.types.mode_t;
import jnr.ffi.types.off_t;
import jnr.ffi.types.size_t;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import ru.serce.jnrfuse.ErrorCodes;
import ru.serce.jnrfuse.FuseFillDir;
import ru.serce.jnrfuse.FuseStubFS;
import ru.serce.jnrfuse.struct.FileStat;
import ru.serce.jnrfuse.struct.FuseFileInfo;
import ru.serce.jnrfuse.struct.Statvfs;

import java.nio.file.Paths;
import java.util.concurrent.atomic.AtomicLong;

public class MainS3Fuse extends FuseStubFS {

    private Logger log = LoggerFactory.getLogger(getClass());


    private AtomicLong id = new AtomicLong(0);

    public void init() {
        log.info("初始化fuse");
    }

    public void destroy() {

    }

    @Override
    public int getattr(String path, FileStat stat) {
        if(path.contains("/.svn/") || path.endsWith("/.svn")){
            return -ErrorCodes.ENOENT();
        }
        log.info("getattr {}", path);
        if(path.equals("/")){
            stat.st_mode.set(FileStat.S_IFDIR | 0777);
            stat.st_uid.set(getContext().uid.get());
            stat.st_gid.set(getContext().gid.get());
            return 0;
        }if(path.equals("/1.txt")){
            stat.st_mode.set(FileStat.S_IFREG | 0777);
            stat.st_uid.set(getContext().uid.get());
            stat.st_gid.set(getContext().gid.get());
            return 0;
        }else{
            return -ErrorCodes.ENOENT();
        }

    }

    @Override
    public int statfs(String path, Statvfs stbuf) {
        if (Platform.getNativePlatform().getOS() == Platform.OS.WINDOWS) {
            if ("/".equals(path)) {
                stbuf.f_blocks.set(1024 * 1024); // total data blocks in file system
                stbuf.f_frsize.set(1024);        // fs block size
                stbuf.f_bfree.set(1024 * 1024);  // free blocks in fs
            }
        }
        return super.statfs(path, stbuf);
    }

    @Override
    public int readdir(String path, Pointer buf, FuseFillDir filter, @off_t long offset, FuseFileInfo fi) {
        log.info("readdir {} {}", path, fi.fh.get());
        filter.apply(buf, ".", null, 0);
        filter.apply(buf, "..", null, 0);
        return 0;
    }

    @Override
    public int open(String path, FuseFileInfo fi) {
        fi.fh.set(id.getAndIncrement());
        log.info("open {}", fi.fh.get());
        return 0;
    }

    @Override
    public int read(String path, Pointer buf, @size_t long size, @off_t long offset, FuseFileInfo fi) {
        return 0;
    }

    @Override
    public int create(String path, @mode_t long mode, FuseFileInfo fi) {
        Long fid = id.getAndIncrement();
        fi.fh.set(fid);
        log.info("create {} {}", path, fi.fh.get());
        return 0;
    }

    @Override
    public int write(String path, Pointer buf, @size_t long size, @off_t long offset,
                     FuseFileInfo fi) {
        log.info("write {} {} {}", path, fi.fh.get(), size);
        final int sz = (int) size;
//        final long fd = fi.fh.get();
        byte[] buffer = new byte[sz];
//        try {
        buf.get(0, buffer, 0, sz);
//            uploadFileToRemote.write(path, fd, buffer);
        return sz;
//        } catch (Exception e) {
//            log.error("while writing to {}.", path, e);
//            return -ErrorCodes.EIO();
//        }

    }

    public int flush(String path, FuseFileInfo fi) {
//        log.info("flush {} {}", path, fi.fh.get());
//        final long fd = fi.fh.get();
//        uploadFileToRemote.flush(path, fd);
        log.info("flush {} {} {}", path, fi.fh.get());
        return 0;
    }

    @Override
    public int mkdir(String path, @mode_t long mode) {
        log.info("mkdir {}", path);
//        s3Service.mkdir(path);
        return 0;
    }

    @Override
    public int rename(String oldPath, String newPath) {
        return 0;
    }

//    @Override
//    public int rmdir(String path) {
//        boolean isSuc = s3Service.rmdir(path);
//        if (isSuc) {
//            return 0;
//        } else {
//            return ErrorCodes.EIO();
//        }
//    }


    @Override
    public int release(String path, FuseFileInfo fi) {
        log.info("release {}", fi.fh.get());
        return 0;
    }

    public void mount(String path) {
        this.mount(Paths.get(path), true, false);
    }

    public void umount() {
        super.umount();
    }

    public static void main(String args[]) {
        MainS3Fuse mainS3Fuse = new MainS3Fuse();
        mainS3Fuse.init();
        mainS3Fuse.mount("E:\\");
    }
}
